import java.io.IOException;

public class Controller {

	private boolean isFlyingOn;

	private int playerTurn = 1;
	private int x;
	private int y;
	private int player1Tokens = 9;
	private int player2Tokens = 9;
	private int[] xRange = new int[2];
	private int[] yRange = new int[2];
	private String[][] validMovesTable = { { "71", "74", "41", "", "" },
			{ "74", "71", "64", "77", "" }, { "77", "74", "43", "", "" },
			{ "62", "42", "64", "", "" }, { "64", "62", "74", "66", "54" },
			{ "66", "64", "46", "", "" }, { "41", "71", "11", "42", "" },
			{ "42", "22", "43", "62", "41" }, { "43", "42", "33", "53", "" },
			{ "45", "46", "35", "55", "" }, { "46", "45", "26", "66", "47" },
			{ "47", "17", "77", "46", "" }, { "33", "43", "34", "", "" },
			{ "34", "33", "35", "24", "" }, { "35", "34", "45", "", "" },
			{ "22", "42", "24", "", "" }, { "24", "22", "34", "26", "14" },
			{ "26", "24", "46", "", "" }, { "11", "41", "14", "", "" },
			{ "14", "11", "24", "17", "" }, { "17", "14", "47", "", "" },
			{ "53", "43", "54", "", "" }, { "54", "53", "55", "64", "" },
			{ "55", "54", "45", "", "" }, { "00" } };

	int[] GridtoBoardLayoutX = { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4,
			5, 5, 5, 6, 6, 6, 7, 7, 7, 0 };
	int[] GridtoBoardLayoutY = { 1, 4, 7, 2, 4, 6, 3, 4, 5, 1, 2, 3, 5, 6, 7,
			3, 4, 5, 2, 4, 6, 1, 4, 7, 0 };

	public Controller(boolean isFlyingOn, int[] xRange, int[] yRange) {
		this.isFlyingOn = isFlyingOn;
		this.x = 0;
		this.y = 0;
		this.xRange = xRange;
		this.yRange = yRange;
	}

	public boolean moveToken(int currentRow, int currentColumn, int desiredRow,
			int desiredColumn, int player) throws IOException {
		int value = Main.getModelSystem().readPosition(desiredRow,
				desiredColumn);
		if (value == 0) {
			if (player == 1 && Global.token1Played != 9) {
				Global.token1Played++;
				Main.getModelSystem().getGame().setToken1Played(Global.token1Played);
			} else if (player == 2 && Global.token2Played != 9) {
				Global.token2Played++;
				Main.getModelSystem().getGame().setToken2Played(Global.token2Played);
			}
			Main.getModelSystem().writePosition(desiredRow, desiredColumn,
					player);
			Main.getModelSystem().writePosition(currentRow, currentColumn, 0);
			if (this.isMill(desiredRow, desiredColumn)) {
				Global.millFormed = true;
			}
			// set return false to make this not blow
			// up. Should return true or false if move
			// is valid.
			else {
				Global.millFormed = false;
				int pTurn = getPlayerTurn();

				if (pTurn == 2) {
					View.playerTurnIcon.setLocation(175, 30);
					// switchTurn();
					// addJLabel(panel,playerTurnIcon,175,30,50,50,Visibility,false);
					try {
						switchTurn();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else if (pTurn == 1) {
					View.playerTurnIcon.setLocation(775, 30);
					try {
						switchTurn();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					// switchTurn();
					// addJLabel(panel,playerTurnIcon,925,30,50,50,Visibility,false);
				}
			}

		}
		return false;

	}

	public int getPlayerTurn() {
		return playerTurn;
	}

	public void setPlayerTurn(int turn) {
		playerTurn = turn;
	}

	public void switchTurn() throws IOException {
		if (playerTurn == 1) {
			playerTurn = 2;
		} else if (playerTurn == 2) {
			playerTurn = 1;
		}
		Main.getModelSystem().getGame().setPlayersTurn(playerTurn);
	}

	public void setPlayerTokens(int tokens1, int tokens2) {
		player1Tokens = tokens1;
		player2Tokens = tokens2;
	}

	/*
	 * This functions determines whether the currently selected piece can move
	 * to new location, selected by the user.
	 * 
	 * @param currentRow The row in the game board data structure that contains
	 * the selected piece.
	 * 
	 * @param currentColumn " column " " ...
	 * 
	 * @param desiredRow The row in the data structure that contains the desired
	 * position for the selected piece.
	 * 
	 * @param desiredColumn " column " " ...
	 * 
	 * @return true of false depending on whether or not the move is valid.
	 */
	public boolean isValidMove(int currentRow, int currentColumn,
			int desiredRow, int desiredColumn) {
		String currentPosition = "" + currentRow + currentColumn;
		String desiredPosition = "" + desiredRow + desiredColumn;

		if (canCurrentPlayerFly()) {
			int value = Main.getModelSystem().readPosition(desiredRow,
					desiredColumn);
			if (value == 0) {
				return true; // The desired position is valid.
			}
			return false;
		}

		if (currentRow == desiredRow && currentColumn == desiredColumn) {
			// do nothing
		} else {
			if (!currentPosition.equals("00")) {
				for (int i = 0; i < 24; i++) { // Find current position in
												// table.
					if (getValidMovesTable()[i][0].equals(currentPosition)) {
						for (int j = 0; j < 5; j++) { // Find desired position
														// in table.
							if (getValidMovesTable()[i][j]
									.equals(desiredPosition)) {
								int value = Main.getModelSystem().readPosition(
										desiredRow, desiredColumn);
								if (value == 0) {
									return true; // The desired position is
													// valid.
								}
							}
						}
						return false;
					}
				}
			} else {
				if (Main.getModelSystem().readPosition(desiredRow,
						desiredColumn) == 0) {
					return true;
				}
				return false;
			}
			return false;
		}
		return false;
	}

	public boolean canCurrentPlayerFly() {
		if (!isFlyingOn())
			return false;

		if (playerTurn == 1) {
			if (player1Tokens < 4) {
				return true;
			} else {
				return false;
			}
		} else {
			if (player2Tokens < 4) {
				return true;
			} else {
				return false;
			}
		}
	}

	public void removeToken(int player) throws IOException {
		if (player == 1) {
			player2Tokens--;
		} else {
			player1Tokens--;
		}
		Main.getModelSystem().adjustTokensLeft(player1Tokens, player2Tokens);
		if (isWin()) {
		}
		//Global.removeToken = true;
	}

	public boolean isMill(int newRow, int newColumn) {
		int caseValueConversion = newRow * 10 + newColumn;
		int newValue = cleanGetBoardLayout()[newRow][newColumn];
		switch (caseValueConversion) {
		case 11:
			if (((newValue == cleanGetBoardLayout()[1][4]) && (newValue == cleanGetBoardLayout()[1][7]))
					|| ((newValue == cleanGetBoardLayout()[4][1]) && (newValue == cleanGetBoardLayout()[7][1])))
				return true;
			break;
		case 14:
			if (((newValue == cleanGetBoardLayout()[1][1]) && (newValue == cleanGetBoardLayout()[1][7]))
					|| ((newValue == cleanGetBoardLayout()[2][4]) && (newValue == cleanGetBoardLayout()[3][4])))
				return true;
			break;
		case 17:
			if (((newValue == cleanGetBoardLayout()[1][1]) && (newValue == cleanGetBoardLayout()[1][4]))
					|| ((newValue == cleanGetBoardLayout()[4][7]) && (newValue == cleanGetBoardLayout()[7][7])))
				return true;
			break;
		case 22:
			if (((newValue == cleanGetBoardLayout()[4][2]) && (newValue == cleanGetBoardLayout()[6][2]))
					|| ((newValue == cleanGetBoardLayout()[2][4]) && (newValue == cleanGetBoardLayout()[2][6])))
				return true;
			break;
		case 24:
			if (((newValue == cleanGetBoardLayout()[1][4]) && (newValue == cleanGetBoardLayout()[3][4]))
					|| ((newValue == cleanGetBoardLayout()[2][2]) && (newValue == cleanGetBoardLayout()[2][6])))
				return true;
			break;
		case 26:
			if (((newValue == cleanGetBoardLayout()[2][2]) && (newValue == cleanGetBoardLayout()[2][4]))
					|| ((newValue == cleanGetBoardLayout()[4][6]) && (newValue == cleanGetBoardLayout()[6][6])))
				return true;
			break;
		case 33:
			if (((newValue == cleanGetBoardLayout()[3][4]) && (newValue == cleanGetBoardLayout()[3][5]))
					|| ((newValue == cleanGetBoardLayout()[4][3]) && (newValue == cleanGetBoardLayout()[5][3])))
				return true;
			break;
		case 34:
			if (((newValue == cleanGetBoardLayout()[2][4]) && (newValue == cleanGetBoardLayout()[1][4]))
					|| ((newValue == cleanGetBoardLayout()[3][3]) && (newValue == cleanGetBoardLayout()[3][5])))
				return true;
			break;
		case 35:
			if (((newValue == cleanGetBoardLayout()[3][4]) && (newValue == cleanGetBoardLayout()[3][3]))
					|| ((newValue == cleanGetBoardLayout()[4][5]) && (newValue == cleanGetBoardLayout()[5][5])))
				return true;
			break;
		case 41:
			if (((newValue == cleanGetBoardLayout()[1][1]) && (newValue == cleanGetBoardLayout()[7][1]))
					|| ((newValue == cleanGetBoardLayout()[4][2]) && (newValue == cleanGetBoardLayout()[4][3])))
				return true;
			break;
		case 42:
			if (((newValue == cleanGetBoardLayout()[4][1]) && (newValue == cleanGetBoardLayout()[4][3]))
					|| ((newValue == cleanGetBoardLayout()[2][2]) && (newValue == cleanGetBoardLayout()[6][2])))
				return true;
			break;
		case 43:
			if (((newValue == cleanGetBoardLayout()[4][1]) && (newValue == cleanGetBoardLayout()[4][2]))
					|| ((newValue == cleanGetBoardLayout()[3][3]) && (newValue == cleanGetBoardLayout()[5][3])))
				return true;
			break;
		case 45:
			if (((newValue == cleanGetBoardLayout()[3][5]) && (newValue == cleanGetBoardLayout()[5][5]))
					|| ((newValue == cleanGetBoardLayout()[4][6]) && (newValue == cleanGetBoardLayout()[4][7])))
				return true;
			break;
		case 46:
			if (((newValue == cleanGetBoardLayout()[4][5]) && (newValue == cleanGetBoardLayout()[4][7]))
					|| ((newValue == cleanGetBoardLayout()[2][6]) && (newValue == cleanGetBoardLayout()[6][6])))
				return true;
			break;
		case 47:
			if (((newValue == cleanGetBoardLayout()[4][5]) && (newValue == cleanGetBoardLayout()[4][6]))
					|| ((newValue == cleanGetBoardLayout()[1][7]) && (newValue == cleanGetBoardLayout()[7][7])))
				return true;
			break;
		case 53:
			if (((newValue == cleanGetBoardLayout()[4][3]) && (newValue == cleanGetBoardLayout()[3][3]))
					|| ((newValue == cleanGetBoardLayout()[5][4]) && (newValue == cleanGetBoardLayout()[5][5])))
				return true;
			break;
		case 54:
			if (((newValue == cleanGetBoardLayout()[5][3]) && (newValue == cleanGetBoardLayout()[5][5]))
					|| ((newValue == cleanGetBoardLayout()[6][4]) && (newValue == cleanGetBoardLayout()[7][4])))
				return true;
			break;
		case 55:
			if (((newValue == cleanGetBoardLayout()[5][3]) && (newValue == cleanGetBoardLayout()[5][4]))
					|| ((newValue == cleanGetBoardLayout()[3][5]) && (newValue == cleanGetBoardLayout()[4][5])))
				return true;
			break;
		case 62:
			if (((newValue == cleanGetBoardLayout()[2][2]) && (newValue == cleanGetBoardLayout()[4][2]))
					|| ((newValue == cleanGetBoardLayout()[6][4]) && (newValue == cleanGetBoardLayout()[6][6])))
				return true;
			break;
		case 64:
			if (((newValue == cleanGetBoardLayout()[6][2]) && (newValue == cleanGetBoardLayout()[6][6]))
					|| ((newValue == cleanGetBoardLayout()[5][4]) && (newValue == cleanGetBoardLayout()[7][4])))
				return true;
			break;
		case 66:
			if (((newValue == cleanGetBoardLayout()[6][2]) && (newValue == cleanGetBoardLayout()[6][4]))
					|| ((newValue == cleanGetBoardLayout()[2][6]) && (newValue == cleanGetBoardLayout()[4][6])))
				return true;
			break;
		case 71:
			if (((newValue == cleanGetBoardLayout()[1][1]) && (newValue == cleanGetBoardLayout()[4][1]))
					|| ((newValue == cleanGetBoardLayout()[7][4]) && (newValue == cleanGetBoardLayout()[7][7])))
				return true;
			break;
		case 74:
			if (((newValue == cleanGetBoardLayout()[7][1]) && (newValue == cleanGetBoardLayout()[7][7]))
					|| ((newValue == cleanGetBoardLayout()[5][4]) && (newValue == cleanGetBoardLayout()[6][4])))
				return true;
			break;
		case 77:
			if (((newValue == cleanGetBoardLayout()[1][1]) && (newValue == cleanGetBoardLayout()[7][4]))
					|| ((newValue == cleanGetBoardLayout()[1][7]) && (newValue == cleanGetBoardLayout()[4][7])))
				return true;
			break;
		}
		return false;
	}

	public boolean isWin() throws IOException {

		int indexOfPlayer1 = 0;
		int indexOfPlayer2 = 0;

		if (player1Tokens < 3) {

			indexOfPlayer1 = Main
					.getModelSystem()
					.getUserNames()
					.indexOf(
							Main.getModelSystem().getGame().getUsers()[0]
									.getName());
			indexOfPlayer2 = Main
					.getModelSystem()
					.getUserNames()
					.indexOf(
							Main.getModelSystem().getGame().getUsers()[1]
									.getName());
			if(!Global.isPVCMode){
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer1)
				.setGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer1).getGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer2)
				.setGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer2).getGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer2)
				.setWins(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer2).getWins() + 1);
			}
			else{
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer1)
				.setComputerGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer1).getComputerGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer2)
				.setComputerGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer2).getComputerGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer2)
				.setComputerWins(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer2).getComputerWins() + 1);
			}
			String message = "Player 2 Wins!! Please select click File -> new Game to start next game.";
			View.displayNotification(message);
			Main.getModelSystem().updateUserFile();
			Main.getViewSystem().setPVPSetup(true, Global.globalFrame);
			return true;
			
		} 
		else if (player2Tokens < 3) {

			indexOfPlayer1 = Main
					.getModelSystem()
					.getUserNames()
					.indexOf(
							Main.getModelSystem().getGame().getUsers()[0]
									.getName());
			indexOfPlayer2 = Main
					.getModelSystem()
					.getUserNames()
					.indexOf(
							Main.getModelSystem().getGame().getUsers()[1]
									.getName());
			
			if(!Global.isPVCMode){
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer1)
				.setGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer1).getGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer2)
				.setGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer2).getGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer1)
				.setWins(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer1).getWins() + 1);
			}
			
			else{
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer1)
				.setComputerGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer1).getComputerGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer2)
				.setComputerGamesPlayed(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer2).getComputerGamesPlayed() + 1);
				Main.getModelSystem()
				.getUsers()
				.get(indexOfPlayer1)
				.setComputerWins(
						Main.getModelSystem().getUsers()
						.get(indexOfPlayer1).getComputerWins() + 1);
			}
			
			String message = "Player 1 Wins!! Please select click File -> New Game to start new game.";
			View.displayNotification(message);
			Main.getModelSystem().updateUserFile();
			Global.setPanel();
			return true;
		} else {
			return false;
		}
	}

	// Getters & Setters

	public boolean isFlyingOn() {
		return isFlyingOn;
	}

	public void setFlyingOn(boolean isFlyingOn) throws IOException {
		this.isFlyingOn = isFlyingOn;
		if (Main.getModelSystem().getGame() != null)
			Main.getModelSystem().getGame().setFlyingEnabled(isFlyingOn);
	}

	public int[] getGridtoBoardLayoutX() {
		return GridtoBoardLayoutX;
	}

	public void setGridtoBoardLayoutX(int[] gridtoBoardLayoutX) {
		GridtoBoardLayoutX = gridtoBoardLayoutX;
	}

	public int[] getGridtoBoardLayoutY() {
		return GridtoBoardLayoutY;
	}

	public void setGridtoBoardLayoutY(int[] gridtoBoardLayoutY) {
		GridtoBoardLayoutY = gridtoBoardLayoutY;
	}

	public int[][] cleanGetBoardLayout() {
		return Main.getModelSystem().getGame().getBoardLayout();
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int[] getxRange() {
		return xRange;
	}

	public void setxRange(int[] xRange) {
		this.xRange = xRange;
	}

	public int[] getyRange() {
		return yRange;
	}

	public void setyRange(int[] yRange) {
		this.yRange = yRange;
	}

	public String[][] getValidMovesTable() {
		return validMovesTable;
	}

	public void setValidMovesTable(String[][] validMovesTable) {
		this.validMovesTable = validMovesTable;
	}

	public int getPlayer1Tokens() {

		return player1Tokens;
	}

	public int getPlayer2Tokens() {

		return player2Tokens;
	}

}
